home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / msg / msg5.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-11  |  22.6 KB  |  964 lines

  1. /*
  2.  *            M S G 5 . C
  3.  *
  4.  * Functions -
  5.  *    setup        read mailbox file
  6.  *    newmessage    notice & read new mail
  7.  *    overwrit    remove deleted messages from a file by overwriting
  8.  *    undigestify    process an undigestify command
  9.  *    nambinary    build path name for binary parallel file
  10.  *    binbuild    Write out a fresh binary parallel file
  11.  *    binupdate    Update one record of the binary file
  12.  *    binheaderupdate    Update the header of the binary file
  13.  *
  14.  *
  15.  *        R E V I S I O N   H I S T O R Y
  16.  *
  17.  *    09/13/82  MJM    This module split off from msg1.c, to even
  18.  *            the sizes and ease editing.
  19.  *
  20.  *    09/22/82  MJM    Added in most of the support for the parallel
  21.  *            binary map file.
  22.  *
  23.  *    03/16/83  MJM    Added binary update routines, neatened manipulation
  24.  *            of binary box overall.  Faster, too!
  25.  *
  26.  *    11/10/83  DPK    Added Steve Kille (SEK) continuation line fix.
  27.  *
  28.  *    07/15/84  HAW    Made binarybox and memory structures identical.
  29.  *            Added readonly mode.
  30.  */
  31.  
  32. #include "util.h"
  33. #include "mmdf.h"
  34. #include <pwd.h>
  35. #include <signal.h>
  36. #include <sys/stat.h>
  37. #include "./msg.h"
  38. #ifdef V4_2BSD
  39. #include <sys/file.h>
  40. #include <strings.h>
  41. #else V4_2BSD
  42. #include <string.h>
  43. #endif V4_2BSD
  44.  
  45. #ifndef V4_2BSD
  46. sigtype    (*oldhup)();
  47. sigtype    (*oldintr)();
  48. sigtype    (*oldquit)();
  49. #endif
  50.  
  51. #ifndef W_OK
  52. #define    W_OK 2
  53. #endif
  54.  
  55. extern FILE *lk_fopen();
  56.  
  57. /*
  58.  *            S E T U P
  59.  *
  60.  *    This function is called to scan the contents of the mailbox.
  61.  */
  62. setup( setflg)
  63. int     setflg;
  64. {
  65.     char    line[LINESIZE];
  66.     char    name[LINESIZE];
  67.     char    mbox[LINESIZE];
  68.     char    datestr[M_BSIZE];    /* where to save Date field */
  69.     char    fromstr[M_BSIZE];    /* where to save From field */
  70.     char    sndstr[M_BSIZE];    /* where to save Sender field */
  71.     char    tostr[M_BSIZE];        /* where to save To field */
  72.     char    subjstr[M_BSIZE];    /* where to save Subj field */
  73.     char    curhdr[M_BSIZE];    /* Scratch for gothdr() */
  74.     char    digsubject[SIZESUBJ];    /* Scratch for undigest function */
  75.     char    *cpy, *cpz;
  76.     int    needscan;
  77.     unsigned int     inmsg;
  78.     unsigned int    count;
  79.     long    newpos;
  80.     long    curpos;
  81.     int     oldflag = 0;
  82.     int    oldsig;
  83.     static int i;        /* String index */
  84.  
  85.     needscan = inmsg = 0;
  86.  
  87.     switch( setflg )  {
  88.  
  89.     case SETAPND:
  90.         status.ms_time = statb2.st_mtime;
  91.         fseek( filefp, status.ms_eofpos, 0);
  92.         newpos = status.ms_eofpos;
  93.         break;
  94.  
  95.     case SETREAD:
  96.         if( filefp != NULL)  {
  97.             ++oldflag;
  98.             fclose( filefp);
  99.         }
  100.         if( (filefp = fopen( filename, "r")) == NULL)  {
  101.             printf( "can't open '%s'\r\n", filename);
  102.             if( oldflag)  {
  103.                 strcpy( filename, oldfile);
  104.                 filefp = fopen( filename, "r");
  105.             }
  106.             error( "");
  107.         }
  108.         if( binfp != (FILE *)NULL ) {
  109.                 lk_fclose( binfp, binarybox, (char *)0, (char *)0);
  110.             binfp = (FILE *)NULL;
  111.         }
  112.  
  113.         fstat( fileno( filefp), &statb1);
  114.  
  115.         if( statb1.st_size == 0 ) {        /* No mail - exit */
  116.             if( quickexit == ON ) {
  117.                 printf("%s is empty!\n",filename);
  118.                 tt_norm();
  119.                 exit(0);
  120.             }
  121.         }
  122.  
  123.         status.ms_time = statb1.st_mtime;
  124.         if( (statb1.st_mode & S_IFMT) != S_IFREG)
  125.             error( "File is not a regular file.\r\n");
  126.  
  127.         if( access( filename, W_OK ) < 0 ) {
  128.             printf(" Unable to write %s - READONLY mode\r\n",filename);
  129.             readonly = TRUE;
  130.         }
  131.  
  132.         /* Set flags if this is the default mail file */
  133.         mainbox();
  134.  
  135.         /* Build the name of the binary mail index file */
  136.         nambinary( filename );
  137.  
  138.         if( (binfp = fopen( binarybox, "r" )) != NULL )  {
  139.  
  140. #ifndef V4_2BSD
  141.             oldhup = signal(SIGHUP,SIG_IGN);
  142.             oldintr = signal(SIGINT,SIG_IGN);
  143.             oldquit = signal(SIGQUIT,SIG_IGN);
  144. #else
  145.             oldsig = sigsetmask(SPSIGS);
  146. #endif
  147.             binaryvalid = FALSE;
  148.  
  149.             /* Load binary map first */
  150.             if( bprint == ON ) {
  151.                 printf("Loading binary box %s ", binarybox );
  152.                 fflush( stdout );
  153.             }
  154.             /* Read header */
  155.             fread( &status, sizeof(struct status), 1, binfp );
  156.  
  157.             /* Quick hack - change from OLDIDENTITY to
  158.              * IDENTITY can be done by msg */
  159.             if( status.ms_ident == OLDIDENTITY ) {
  160.                 rewind(binfp);
  161.                 fread( &status, sizeof(struct oldstatus),
  162.                     1, binfp );
  163.                 status.ms_markno = 0;
  164.                 /* binbuild will be called below */
  165.             } else if( status.ms_ident != IDENTITY )  {
  166.                 tt_norm();
  167.                 printf("\n\nBinary file version error.");
  168.                 printf("  file=%x, program=%x\n", status.ms_ident, IDENTITY );
  169.                 printf("This version of msg uses a new binary file which is not compatible\n");
  170.                 printf("with the old version. You may either delete the binary\n");
  171.                 printf("file %s and restart msg\n", binarybox );
  172.                 printf("or use the old version of msg. Deleting the binary file\n");
  173.                 printf("will destroy the old status flags but no mail will be lost.\n");
  174.                  printf("The old version may still be used by typing msg.bak but may disappear\n");
  175.                 printf("soon so plan to convert to the new version as soon as possible.\n");
  176.  
  177.                 exit(10);
  178.                 /* NOTREACHED */
  179.             }
  180.  
  181.             /* Read data */
  182.             for( i = 0; i < status.ms_nmsgs; i++ )  {
  183.                 if( (msgp[i] = (struct message *) malloc(sizeof(struct message)) ) == NULL ) {
  184.                     status.ms_nmsgs = i-1;    
  185.                     nomem();
  186.                     /* NOTREACHED */
  187.                 }
  188.  
  189.                 if(fread( msgp[i], sizeof(struct message), 1, binfp ) != 1) {
  190.                     tt_norm();
  191.                     printf("\nThe binary box is corrupted.\n");
  192.                     printf("rm %s and retry 'msg'.\n", binarybox);
  193.                     exit(11);
  194.                 }
  195.  
  196.                 if( bdots == ON && bprint == ON ) {
  197.                     putchar('.');
  198.                     fflush(stdout);
  199.                 }
  200.             }
  201.             /* Quick check of binary box integrity:
  202.              * check for delimiters in last message */
  203.             fseek( filefp, status.ms_eofpos-strlen( delim2 ), 0 );
  204.             if( ( xfgets( line, 2+strlen( delim2 ), filefp ) == NULL )
  205.                 || (strequ( line, delim2 ) == FALSE ))  {
  206.                 tt_norm();
  207.                 printf("\nThe binary box is corrupted.\n");
  208.                 printf("rm %s and retry 'msg'.\n", binarybox);
  209.                 exit(11);
  210.             }
  211.             
  212.             if( bprint == ON ) {
  213.                 printf(" - Done\r\n");
  214.                 fflush( stdout );
  215.             }
  216.  
  217.             if( status.ms_ident == OLDIDENTITY ) {
  218.                 printf("Rebuilding binary box\r\n");
  219.                 binbuild();
  220.             }
  221.  
  222.             /* Proceed with appending the rest of the messages */
  223.             newpos = status.ms_eofpos;
  224.  
  225.             fclose( binfp );
  226.             binfp = (FILE *)NULL;
  227.             binaryvalid = TRUE;
  228. #ifndef V4_2BSD
  229.             signal(SIGHUP,oldhup);
  230.             signal(SIGINT,oldintr);
  231.             signal(SIGQUIT,oldquit);
  232. #else
  233.             sigsetmask(oldsig);
  234. #endif
  235.  
  236.             /* Fall through to read any new messages */
  237.             setflg = SETAPND;    /* to get "new" flags */
  238.  
  239.         }  else  {
  240.  
  241.             printf( "Reading %s ", filename);
  242.             fflush( stdout);
  243.  
  244.             status.ms_curmsg = 0;        /* Global */
  245.             status.ms_nmsgs = 0;        /* Global */
  246.             newpos = status.ms_eofpos = 0;
  247.  
  248.             if( readonly == FALSE )
  249.                 if( (i = creat( binarybox, sentprotect )) < 0 )  {
  250.                     printf("Unable to create %s - READONLY mode\r\n", binarybox );
  251.                     readonly = TRUE;
  252.                 }
  253.                 else
  254.                     close(i);
  255.         }
  256.  
  257.         if( readonly == FALSE ) {
  258.             /* get exclusive control of file */
  259.             if (access(binarybox, W_OK) < 0 ) {
  260.                 printf("Can't write %s - READONLY mode\n",binarybox);
  261.                 readonly = TRUE;
  262.             }
  263.             else if ((binfp = lk_fopen(binarybox, "r+", (char *)0,
  264.                            (char *)0, 5)) == (FILE *) NULL) {
  265.                 printf("%s busy - READONLY mode\n",binarybox);
  266.                 readonly = TRUE;
  267.             }
  268.         }
  269.         break;
  270.  
  271.     case SETUNDIGEST:
  272.         fseek( filefp, mptr->start, 0);
  273.         newpos = mptr->start;
  274.         strncpy( digsubject, mptr->subject, SIZESUBJ );
  275.         break;
  276.  
  277.     default:
  278.         error( "Bad setup()" );
  279.     }
  280.  
  281.     fseek( filefp, newpos, 0 );
  282.     while( xfgets( line, sizeof( line), filefp) != NULL)  {
  283.         curpos = newpos;
  284.         count = strlen( line);
  285.         newpos += count;
  286.  
  287.         /*
  288.          * Check for Message Separators  (Two types)
  289.          */
  290.         if( strequ( line, delim1) || strequ( line, delim2))  {
  291.             if( setflg == SETUNDIGEST )
  292.                 return;
  293.             if( inmsg != 0 )  {
  294.                 /* wants message NUMBER */
  295.                 binupdate( (int)status.ms_nmsgs );
  296.                 status.ms_eofpos = newpos;
  297.             }
  298.             inmsg = 0;
  299.             continue;
  300.         }
  301.  
  302.         if(
  303.             setflg == SETUNDIGEST &&
  304.             strncmp( line, "--------------------", 20 ) == 0
  305.         )  {
  306.             inmsg = 0;
  307.             continue;
  308.         }
  309.  
  310.         /*
  311.          * Note each new message.  If we are not in a message, and
  312.          * a line of non-separator has been found, start off a new
  313.          * message.
  314.          */
  315.         if( inmsg == 0)  {
  316.             if( mdots == ON ) {
  317.                 putchar( '.' );
  318.                 fflush( stdout);
  319.             }
  320.             /* Clear out header scan area */
  321.             datestr[0] =
  322.                 fromstr[0] =
  323.                 sndstr[0] =
  324.                 tostr[0] =
  325.                 subjstr[0] = '\0';
  326.             curhdr[0] = '\0';    /* SEK continuation fix! */
  327.  
  328.             /* scan off leading blank lines */
  329.             while( count == 1)  {
  330.                 xfgets( line, sizeof( line), filefp);
  331.                 curpos = newpos;
  332.                 count = strlen( line);
  333.                 newpos += count;
  334.             }
  335.  
  336.             /* Build new table entry */
  337.             if( status.ms_nmsgs >= Nmsgs)  {
  338.                 printf("More than %d messages in file.\r\n", Nmsgs);
  339.                 status.ms_nmsgs--;
  340.                 nomem();
  341.                 /* NOTREACHED */
  342.             }
  343.  
  344.             /*
  345.              * Allocate a new msgp slot, either at the end of the
  346.              * messages, or in the middle, depending.
  347.              */
  348.             if( setflg != SETUNDIGEST )  {
  349.                 if( (mptr = msgp[status.ms_nmsgs++] = (struct message *) malloc(sizeof(struct message)) ) == NULL ) {
  350.                     status.ms_nmsgs--;
  351.                     nomem();
  352.                     /* NOTREACHED */
  353.                 }
  354.                 mptr->flags = 0;
  355.             }  else  {
  356.                 /*
  357.                  * scrunch down.
  358.                  *   msgno is current message NUMBER
  359.                  *   status.ms_nmsgs is last message NUMBER.
  360.                  * offsets are one less than numbers.
  361.                  */
  362.                 if( (mptr = msgp[status.ms_nmsgs] = (struct message *) malloc(sizeof(struct message)) ) == NULL ) {
  363.                     error("Out of memory - operation aborted\n");
  364.                     /* NOTREACHED */
  365.                 }
  366.                 
  367.                 for( i = status.ms_nmsgs-1; i >= msgno; i-- )  {
  368.                     msgp[i+1] = msgp[i];
  369.                 }
  370.                 status.ms_nmsgs++;
  371.                 msgp[ msgno++ ] = mptr;
  372.                 mptr->flags = M_NEW;
  373.             }
  374.  
  375.             mptr->start = curpos;
  376.             mptr->len = 0L;
  377.             mptr->date = 0L;
  378.             mptr->from[0] = mptr->datestr[0] = mptr->subject[0] = mptr->to[0] = '\0';
  379.  
  380.             needscan = 1;
  381.             inmsg++;
  382.         }
  383.         mptr->len += count;
  384.  
  385.         if( count == 1 && needscan)  {
  386.             /*
  387.              * Blank line found while reading header.
  388.              * Digest header information and store results
  389.              * into msgp[] structure entry.
  390.              */
  391.  
  392.             /* Process date field( if any) */
  393.             if( !isnull( datestr[0])) {
  394.                 if( (mptr->date = smtpdate( datestr )) != -1L)
  395.                     makedate( &mptr->date, mptr->datestr);
  396.             }
  397.  
  398.             /* Process to field ( if any ) */
  399.             if( !isnull( tostr[0] ) ) {
  400.                 strncpy( mptr->to, tostr, SIZETO );
  401.                 mptr->to[SIZETO-1] = '\0';
  402.             }
  403.  
  404.             /* Process from field( if any) */
  405.             if( !isnull( fromstr[0]))  {
  406.                 parsadr( fromstr, name, mbox, (char *)0);
  407.  
  408.                 if( prefix( username, mbox) && !isnull( tostr[0]))  {
  409.                     /* sender was self */
  410.                     parsadr(tostr, name, mbox,( char *) 0);
  411.                     if( !isnull( name[0]))
  412.                         sprintf( fromstr, "To: %s%c", name, '\0');
  413.                     else
  414.                         sprintf( fromstr, "To: %s%c", mbox, '\0');
  415.                 }  else  {
  416.                     if( !isnull( name[0]))
  417.                         strncpy(fromstr,name,SIZEFROM);
  418.                     else
  419.                         strncpy(fromstr,mbox,SIZEFROM);
  420.                 }
  421.                 mptr->from[SIZEFROM-1] = '\0';
  422.                 /* Try to eliminate UUCP prefixes */
  423.                 {
  424.                     register char *cp;
  425.                     char * indent;
  426.  
  427.                     indent = cp = fromstr;
  428.                     while( *cp )
  429.                         if( *cp++ == '!' )
  430.                             indent = cp;
  431.  
  432.                     strncpy(mptr->from,indent,SIZEFROM-1);
  433.                 }
  434.  
  435.                 mptr->flags |= M_NEW;
  436.             }
  437.  
  438.             /* Process Subject field, if any */
  439.             if( !isnull( subjstr[0]))  {
  440.                 subjstr[M_BSIZE-1] = '\0';
  441.                 if( (cpz = index(subjstr,'\n')) != 0 )
  442.                     *cpz = '\0';
  443.                 if( filoutflag == ON ) {
  444.                     for(cpz = subjstr,cpy = mptr->subject;
  445.                         (*cpz != '\0') && (cpy - mptr->subject < SIZESUBJ);
  446.                         cpz++ ) {
  447.                         if( *cpz < ' ' || *cpz == '\177' ) {
  448.                             *cpy++ = '^';
  449.                             *cpy++ = '@' + *cpz;
  450.                         }
  451.                         else
  452.                             *cpy++ = *cpz;
  453.                     }
  454.                     *cpy = '\0';
  455.                 }
  456.                 else
  457.                     strncpy( mptr->subject, subjstr, SIZESUBJ );
  458.                 mptr->subject[SIZESUBJ-1] = '\0';
  459.             }
  460.  
  461.             /* Header scan complete */
  462.             needscan = 0;
  463.         }
  464.  
  465.         /* This line is part of the header -- scan it */
  466.         if( needscan && line[0] != '\n' )  {
  467.             gothdr( curhdr, "date:", line, datestr);
  468.             gothdr( curhdr, "from:", line, fromstr);
  469.             gothdr( curhdr, "sender:", line, sndstr);
  470.             gothdr( curhdr, "To:", line, tostr);
  471.             gothdr( curhdr, "subject:", line, subjstr);
  472.         }
  473.     }
  474.     fstat( fileno( filefp), &statb1);
  475.     status.ms_time = statb1.st_mtime;
  476.  
  477.     /*
  478.      * Check for having read a message while it was being delivered.
  479.      * Exclusive opens might be better, but for now...
  480.      */
  481.     if( inmsg != 0 )  {
  482.         printf("(partial message ignored) ");
  483.         free( (char *) msgp[--status.ms_nmsgs]);
  484.     }
  485.  
  486.     printf( " %d message%c total.\r\n", status.ms_nmsgs, status.ms_nmsgs == 1 ? ' ' : 's');
  487.  
  488.     /*
  489.      * rewrite entire binary file if we expanded the middle of the
  490.      * table with an undigestify operation.  SETREAD and SETAPND handled
  491.      * inside loop, with a binupdate() after each new message.
  492.      */
  493.     if( readonly == FALSE ) {
  494.         if( setflg == SETUNDIGEST )
  495.             binbuild();
  496.         else
  497.             binheaderupdate();
  498.         fflush( binfp );
  499.     }
  500. }
  501.  
  502. /*
  503.  *            N E W M E S S A G E
  504.  *
  505.  * notice & include new mail
  506.  */
  507. newmessage()
  508. {
  509.     /* Might also be useful to check the sizes */
  510.     if( filefp == NULL ||
  511.         fstat( fileno( filefp), &statb2) < 0 ||
  512.         statb2.st_mtime == status.ms_time
  513.     ) {
  514.         return;        /* nothing new */
  515.     }
  516.     printf( "Reading new messages ");
  517.     setup( SETAPND );        /* incorporate appended messages */
  518. }
  519.  
  520. /*
  521.  *            V P U T M S G
  522.  *
  523.  * This routine gives a visual indication of each message being written
  524.  * out, with one dot per message.  Makes the user feel better about the
  525.  * often longish wait.
  526.  *
  527.  * This routine is really intended only for the use of the overwrite function,
  528.  * as it records the NEW position of of the message in the file, to avoid
  529.  * guesswork about message lengths in overwrite().
  530.  */
  531. vputmsg()
  532. {
  533.     long pos, ftell();
  534.     char tbuf[1024];
  535.     register int tt;
  536.         
  537.     if( mdots == ON ) {
  538.         putchar('.');
  539.         fflush( stdout );
  540.     }
  541.  
  542.     fputs( delim1, outfp );
  543.  
  544.     pos = ftell( outfp );
  545.     if( mptr->flags & M_RESTMAIL ) {
  546.         /* Write the rest of the mail file */
  547.         fseek(filefp, mptr->start, 0);
  548.         while( (tt = fread(tbuf, sizeof(char), sizeof(tbuf), filefp)) == sizeof(tbuf) )
  549.             fwrite(tbuf, sizeof(char), strlen(tbuf), outfp);
  550.         fwrite(tbuf,sizeof(char), tt, outfp);
  551.     }
  552.     else {
  553.         writmsg();
  554.         fputs( delim2, outfp );
  555.     }
  556.     mptr->start = pos;
  557. }
  558.  
  559. /*
  560.  *            O V E R W R I T
  561.  *
  562.  * remove deleted messages from file.
  563.  *
  564.  * Note that vputmsg() above updates the message start position info.
  565.  */
  566. overwrit()
  567. {
  568.     static char tempfile[128];    /* build name of temporary file */
  569.     unsigned int ndeleted;
  570.     unsigned int i,ii;
  571.     static char *ptr;
  572.     register struct message **inp, **outp;    /* For mashing table */
  573.     
  574.     if( readonly == TRUE )
  575.         error("READONLY mode - overwrite ignored\n");
  576.  
  577.     for( ndeleted = 0, i = status.ms_nmsgs; i-- != 0; ) {
  578.         if( msgp[i]->flags & M_RESTMAIL )
  579.             msgp[i]->flags &= ~M_DELETED;
  580.  
  581.         if( msgp[i]->flags & M_DELETED )
  582.             ndeleted++;        /* how many dead messages */
  583.     }
  584.     
  585.     if( ndeleted == 0)  {
  586.         printf( "file unchanged, so not updated\r\n");
  587.         return;
  588.     }
  589.  
  590.     if( outmem == FALSE && stat( filename, &statb2) >= 0 && status.ms_time != statb2.st_mtime)  {
  591.             /* Leave the processing to newmessage() */
  592.             /* We can't just return here, because this is called
  593.              * from the "exit" command...
  594.              */
  595.             error( "File updated since last read...\r\n");
  596.     }
  597.  
  598.     /* get exclusive control of file */
  599.     if( (exclfd = lk_open( filename, 1, (char *)0, (char *)0, 5))
  600.          < 0 && errno == ETXTBSY)  {
  601.         printf( "'%s' busy; try later", filename);
  602.         error( "\r\n");
  603.     }
  604.  
  605.     if( ndeleted == status.ms_nmsgs)  {
  606.         /*
  607.          *  All the messages are deleted.
  608.          *  Truncate (always if mailbox), otherwise delete
  609.          */
  610.         printf("All messages deleted from %s.\r\n", filename );
  611.         if( ismainbox)  {
  612.             creat( filename, sentprotect);
  613.             creat( binarybox, sentprotect );
  614.         }  else  {
  615.             printf( "delete %s", filename);
  616.             /* for safety... */
  617.             if( confirm((char *)0,DOLF))  {
  618.                 unlink( filename );
  619.                 unlink( binarybox );
  620.             }
  621.             else {
  622.                 creat( filename, sentprotect);
  623.                 creat( binarybox, sentprotect );
  624.             }
  625.         }
  626.     }  else  {
  627.         strcpy( tempfile, filename);
  628.         /* get the path to directory of file  */
  629.         if (ptr = rindex(tempfile, '/'))
  630.             *++ptr = '\0';
  631.         else
  632.             ptr = tempfile;
  633.         strcpy(ptr, tempname);
  634.         mktemp(tempfile);
  635.  
  636.         if( (outfd = creat( tempfile, sentprotect)) < 0)
  637.             error( "can't create temporary file\r\n");
  638.  
  639.         if( (outfp = fdopen( outfd, "w" )) == NULL )
  640.             error( "can't fdopen temp file\n" );
  641.         outfd = -1;
  642.  
  643.         /* save the undeleted messages */
  644.         printf("OverWriting %s ", filename);
  645.         unset();
  646.         settype( 'u' );
  647.         doiter( vputmsg );
  648.         status.ms_eofpos = ftell(outfp);
  649.         fclose( outfp );
  650.         if( unlink( filename) < 0)
  651.             error( "can't delete old file\r\n");
  652.         if( link( tempfile, filename) < 0)  {
  653.             printf( "can't rename temporary file '%s' to be '%s'.\r\n",
  654.             tempfile, filename);
  655.             error( "The temporary file still exists.\r\n");
  656.         }
  657.         unlink( tempfile);
  658.     }
  659.     if( exclfd >= 0 ) {
  660.         lk_close( exclfd, filename, NULL, NULL);
  661.         if( stat( filename, &statb2 ) >= 0 )
  662.             status.ms_time = statb2.st_mtime;
  663.     }
  664.  
  665.     /* Mash table down to reflect new file layout */
  666.     inp = &msgp[0];
  667.     outp = &msgp[0];
  668.     ndeleted = 0;
  669.     i = status.ms_curmsg;
  670.     ii = status.ms_markno;
  671.     for( msgno = 1; msgno <= status.ms_nmsgs; msgno++ )  {
  672.     
  673.         if( (*inp)->flags & M_DELETED )  {
  674.             ndeleted++;
  675.             free(*inp++);
  676.             if( msgno < i )
  677.                 status.ms_curmsg--;
  678.             if( msgno < ii )
  679.                 status.ms_markno--;
  680.         }  else  {
  681.             /* Note that position changes are done by vputmsg() */
  682.             /*
  683.              * If the input and output slots are different,
  684.              * clean up the input slot.  (Else we clobber
  685.              * ourselves!).
  686.              */
  687.             if( (*inp) != (*outp) )  {
  688.                 *outp = *inp;
  689.             }
  690.             inp++;
  691.             outp++;
  692.         }
  693.     }
  694.  
  695.     /* Adjust current message so as not to run off end */
  696.     status.ms_nmsgs -= ndeleted;
  697.     if( status.ms_curmsg > status.ms_nmsgs )
  698.         status.ms_curmsg = status.ms_nmsgs;
  699.  
  700.     if( status.ms_markno > status.ms_nmsgs )
  701.         status.ms_markno = status.ms_curmsg;
  702.         
  703.     if( status.ms_nmsgs == 0 ) {
  704.         status.ms_curmsg = 0;
  705.         return;
  706.     }
  707.  
  708.     fclose( filefp );
  709.     if( (filefp = fopen( filename, "r" )) == NULL )
  710.         error("Unable to re-open file");
  711.  
  712.     fstat( fileno( filefp ), &statb1 );
  713.     status.ms_time = statb1.st_mtime;
  714.  
  715.     printf( " %d message%c total.\r\n", status.ms_nmsgs, status.ms_nmsgs == 1 ? ' ' : 's');
  716.  
  717.     if( outmem == TRUE ) {
  718.         /* Alter the status struct so the rest of the msgs will
  719.          *  be recovered by newmessage()
  720.          */
  721.         for( i = status.ms_nmsgs; i-- != 0; )
  722.             if( msgp[i]->flags & M_RESTMAIL )
  723.                 status.ms_eofpos = msgp[i]->start;
  724.         status.ms_nmsgs--;
  725.         status.ms_time = 0;
  726.     }
  727.  
  728.     /*
  729.      * At this point, the rest of the program should not even
  730.      * know that anything has happened.  Things should be in
  731.      * a good enough state that everything else works normally.
  732.      */
  733.     /* Update the binary file */
  734.     binbuild();
  735. }
  736.  
  737. /*
  738.  *            U N D I G E S T I F Y
  739.  */
  740. undigestify()
  741. {
  742.     /* mptr set by doiter for setup() */
  743.     delmsg();
  744.     setup( SETUNDIGEST );
  745. }
  746.  
  747.  
  748. /*
  749.  *            N A M B I N A R Y
  750.  *
  751.  * Build the name of the associated binary file, and save the name
  752.  * in the string "binarybox".
  753.  */
  754. nambinary( arg )
  755. register char *arg;
  756. {
  757.     register char *sav, *cp;
  758.     char ending[32];
  759.     char fname[72];
  760.  
  761.     ending[0] = fname[0] = 0;
  762.     strcpy( fname, arg );
  763.  
  764.     /* Find the last path component */
  765.     sav = cp = fname;
  766.     while( *cp )
  767.         if( *cp++ == '/' )
  768.             sav = cp;
  769.  
  770.     if( sav == fname )  {
  771.         /* No slashes found in path name */
  772.         sprintf( binarybox, "%s%s", binarypre, fname );
  773.     }  else  {
  774.         strcpy( ending, sav );
  775.         *(sav-1) = 0;
  776.  
  777.         sprintf( binarybox, "%s/%s%s", fname, binarypre, ending );
  778.     }
  779. }
  780.  
  781. /*
  782.  *            B I N B U I L D
  783.  *
  784.  * Rewrite the entire binary file, including the header.
  785.  */
  786. binbuild()
  787. {
  788.     static char tempfile[128];    /* build name of temporary file */
  789.     register int i;
  790.     char *ptr;
  791.     int oldsig;
  792.  
  793.     if( readonly == TRUE )
  794.         return;
  795.  
  796.     if( binfp != (FILE *) NULL ) {
  797.         lk_fclose( binfp, binarybox, (char *)0, (char *)0 );
  798.         binfp = (FILE *)NULL;
  799.     }
  800.  
  801.     /* Don't bother making a new binary file if mailbox is empty */
  802.     if( status.ms_nmsgs <= 0 )  {
  803.         unlink( binarybox );
  804.         return;
  805.     }
  806.  
  807. #ifndef V4_2BSD
  808.     oldhup = signal(SIGHUP,SIG_IGN);
  809.     oldintr = signal(SIGINT,SIG_IGN);
  810.     oldquit = signal(SIGQUIT,SIG_IGN);
  811. #else
  812.     oldsig = sigsetmask(SPSIGS);    /* Block all signals */
  813. #endif
  814.     strcpy( tempfile, binarybox);
  815.     /* get the path to directory of file  */
  816.     if (ptr = rindex(tempfile, '/'))
  817.         *++ptr = '\0';
  818.     else
  819.         ptr = tempfile;
  820.     strcpy(ptr, tempname);
  821.     mktemp(tempfile);
  822.  
  823.     if( (i = creat( tempfile, sentprotect )) < 0 )
  824.         error("Unable to create temporary file\r\n");
  825.  
  826.     if( (binfp = fdopen( i, "w" )) == NULL )
  827.             error( "can't fdopen temp file\n" );
  828.  
  829.     if( bprint == ON ) {
  830.         printf("Writing binary file:");
  831.         fflush (stdout);
  832.     }
  833.  
  834.     binheaderupdate();
  835.  
  836.     for( i=0; i < status.ms_nmsgs; i++ )  {
  837.         fwrite( msgp[i], sizeof(struct message), 1, binfp );
  838.         if( bdots == ON && bprint == ON ) {
  839.             putchar( '.' );
  840.             fflush( stdout );
  841.         }
  842.     }
  843.     fclose( binfp );
  844.     if( unlink( binarybox ) < 0)
  845.             error( "can't delete old binarybox\r\n");
  846.     if( link( tempfile, binarybox ) < 0)  {
  847.         printf( "can't rename temporary file '%s' to be '%s'.\r\n",
  848.             tempfile, binarybox);
  849.         error( "The temporary file still exists.\r\n");
  850.     }
  851.     unlink( tempfile);
  852.  
  853.     if( (binfp = lk_fopen( binarybox, "r+", (char *)0, 
  854.                       (char *)0, 5 )) == (FILE *) NULL )
  855.         error("Can't re-open binary box\r\n");
  856.  
  857.     if( bprint == ON )
  858.         printf(" done\r\n");
  859.     fflush( stdout );
  860. #ifndef V4_2BSD
  861.     signal(SIGHUP,oldhup);
  862.     signal(SIGINT,oldintr);
  863.     signal(SIGQUIT,oldquit);
  864. #else
  865.     sigsetmask(oldsig);    /* restore signals */
  866. #endif
  867. }
  868.  
  869. /*
  870.  *            B I N U P D A T E
  871.  *
  872.  * Update a single message in the binary box.
  873.  * The number given is in the range 1...nmsgs.
  874.  */
  875. binupdate( number )
  876. int number;
  877. {
  878.     long place;
  879.  
  880.     if( readonly == TRUE )
  881.         return;
  882.  
  883.     if( number <= 0 || number > Nmsgs )
  884.         printf("binupdate(%d): out of range\n", number);
  885.  
  886.     if( binfp == (FILE *) NULL )  {
  887.         printf("binupdate: opening binary box\n");
  888.         if( (binfp = lk_fopen( binarybox, "r+", (char *)0,
  889.                       (char *)0, 5 )) == (FILE *) NULL ) {
  890.             printf("binupdate: unable to open binary box");
  891.             fflush(stdout);
  892.             return;
  893.         }
  894.     }    
  895.  
  896.     place = (number-1) * sizeof(struct message) + sizeof(struct status);
  897.     if( fseek( binfp, place, 0) < 0 )
  898.         printf("binupdate: fseek error\n");
  899.  
  900.     fwrite( msgp[number-1], sizeof(struct message), 1, binfp );
  901. }
  902.  
  903. /*
  904.  *            B I N H E A D E R U P D A T E
  905.  */
  906. binheaderupdate()
  907. {
  908.     if( readonly == TRUE )
  909.         return;
  910.  
  911.     /* Build header record */
  912.     fseek( binfp, (long) 0, 0 );
  913.     status.ms_ident = IDENTITY;
  914.     fwrite( &status, sizeof(struct status), 1, binfp );
  915. }
  916.  
  917. /*            N O M E M
  918.  *  
  919.  *  Recover gracefully when out of memory
  920.  */
  921. nomem() {
  922.  
  923.     struct message **sp;
  924.     long ls;
  925.  
  926.     /* Find the last msg; not always the "last" one */
  927.     ls = msgp[0]->start;
  928.     for( sp = &msgp[1]; sp < &msgp[status.ms_nmsgs]; sp++ ) {
  929.         if( (*sp)->start > ls ) {
  930.             mptr = (*sp);
  931.             ls = (*sp)->start;
  932.         }
  933.     }
  934.  
  935.     mptr->flags |= M_RESTMAIL;
  936.     outmem = TRUE;
  937.     printf("\n\007***********************************************\n");
  938.     printf("\007Out of memory - Move or delete existing messages then overwrite\n");
  939.     printf("Additional messages will appear after the overwrite!\n");
  940.     error("\007***********************************************\n");
  941.     /* NOTREACHED */
  942. }
  943.  
  944. setmbox(file)
  945. register char *file;
  946. {
  947.     strcpy(defmbox, file);
  948.     strcpy(defoutfile, file);
  949.     ismainbox++;
  950. }
  951.  
  952. closeup(status)
  953. register int status;
  954. {
  955.     if (binfp != (FILE *) NULL)
  956.         if (readonly == TRUE)
  957.             fclose(binfp);
  958.         else
  959.             lk_fclose(binfp, binarybox, (char *)0, (char *)0);
  960.     exit(status);
  961.  
  962.     /* NOT REACHED */
  963. }
  964.